﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Runtime.InteropServices;
using System.Windows.Forms;
public class myScreen
{
    public WinApi.DEVMODE DeviceMode;
     public WinApi.DISPLAY_DEVICE ScreenDevice;
    public string DeviceName;
    public bool IsPrimary;
    public int ScreenWidth;
    public int ScreenHeight;
    public int XPosition;
      public int YPosition;
}
public class ScreenHelper
{
    public static List<myScreen> myGetAllScreen()
    {
        List<WinApi.DISPLAY_DEVICE> devices = new List<WinApi.DISPLAY_DEVICE>();
        List<myScreen> screens = new List<myScreen>();
        bool error = false;
        //Here I am listing all DisplayDevices (Monitors)
        for (int devId = 0; !error; devId++)
        {
            try
            {
                WinApi.DISPLAY_DEVICE device = new WinApi.DISPLAY_DEVICE();
                device.cb = Marshal.SizeOf(typeof(WinApi.DISPLAY_DEVICE));
                error = !WinApi.User_32.EnumDisplayDevices(null, devId, ref device, 0);
                if ((device.StateFlags & WinApi.DisplayDeviceStateFlags.AttachedToDesktop) == WinApi.DisplayDeviceStateFlags.AttachedToDesktop)
                {
                    devices.Add(device);
                }
            }
            catch (Exception)
            {
                error = true;
            }
        }

        devices.ForEach(d => {
            WinApi.DEVMODE ndm = NewDevMode();
            WinApi.User_32.EnumDisplaySettings(d.DeviceName, (int)WinApi.DEVMODE_SETTINGS.ENUM_REGISTRY_SETTINGS, ref ndm);
            screens.Add(new myScreen()
            {
                DeviceMode = ndm,
                ScreenDevice = d,
                DeviceName = d.DeviceName,
                IsPrimary = ((d.StateFlags & WinApi.DisplayDeviceStateFlags.PrimaryDevice) == WinApi.DisplayDeviceStateFlags.PrimaryDevice),
                ScreenWidth = (int)ndm.dmPelsWidth,
                ScreenHeight = (int)ndm.dmPelsHeight,
                XPosition = (int)ndm.dmPosition.x,
                YPosition = (int)ndm.dmPosition.y
            });
        });

        return screens;
    }

    public static void SetPrimaryScreen(string deviceName)
    {
        List<myScreen> screenList = myGetAllScreen();
        myScreen primaryScreen = GetPrimaryScreen(screenList);
        if (primaryScreen.ScreenDevice.DeviceName == deviceName)
            return;

        myScreen newPrimaryScreen = GetScreen(deviceName);

        SwitchPrimaryScreen(newPrimaryScreen, primaryScreen);

    }

    public static myScreen GetPrimaryScreen(List<myScreen> devices)
    {
        foreach (myScreen d in devices)
        {
            if ((d.ScreenDevice.StateFlags & WinApi.DisplayDeviceStateFlags.PrimaryDevice) == WinApi.DisplayDeviceStateFlags.PrimaryDevice)
            {
                return d;
            }
        }
        return null;
    }

    public static List<myScreen> GetUnPrimaryScreen(List<myScreen> devices)
    {
        List<myScreen> dList = new List<myScreen>();

        foreach (myScreen d in devices)
        {
            if ((d.ScreenDevice.StateFlags & WinApi.DisplayDeviceStateFlags.PrimaryDevice) != WinApi.DisplayDeviceStateFlags.PrimaryDevice)
            {
                dList.Add(d);
            }
        }
        return dList;
    }

    public static myScreen GetScreen(string deviceName)
    {
        List<myScreen> screenList = myGetAllScreen();
        return screenList.Where(p => p.ScreenDevice.DeviceName == deviceName).FirstOrDefault();
    }

    private static void SwitchPrimaryScreen(myScreen newPrimary, myScreen oldPrimary)
    {
        MoveOldPrimary(newPrimary, oldPrimary);
        MoveNewPrimary(newPrimary, oldPrimary);
        CommitChange(newPrimary, oldPrimary);
    }

    private static void MoveOldPrimary(myScreen newPrimary, myScreen oldPrimary)
    {
        WinApi.DEVMODE ndm3 = NewDevMode();
        ndm3.dmFields = WinApi.DEVMODE_Flags.DM_POSITION;
        ndm3.dmPosition.x = (int)newPrimary.DeviceMode.dmPelsWidth;
        ndm3.dmPosition.y = 0;

        WinApi.User_32.ChangeDisplaySettingsEx(oldPrimary.ScreenDevice.DeviceName, ref ndm3, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY | (int)WinApi.DeviceFlags.CDS_NORESET, IntPtr.Zero);

    }

    private static void MoveNewPrimary(myScreen newPrimary, myScreen oldPrimary)
    {
        WinApi.DEVMODE ndm4 = NewDevMode();
        ndm4.dmFields = WinApi.DEVMODE_Flags.DM_POSITION;
        ndm4.dmPosition.x = 0;
        ndm4.dmPosition.y = 0;
        WinApi.User_32.ChangeDisplaySettingsEx(newPrimary.ScreenDevice.DeviceName, ref ndm4, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_SET_PRIMARY | (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY | (int)WinApi.DeviceFlags.CDS_NORESET, IntPtr.Zero);
    }

    private static void CommitChange(myScreen newPrimary, myScreen oldPrimary)
    {
        WinApi.DEVMODE ndm5 = NewDevMode();
        WinApi.User_32.ChangeDisplaySettingsEx(oldPrimary.ScreenDevice.DeviceName, ref ndm5, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY, (IntPtr)null);

        WinApi.DEVMODE ndm6 = NewDevMode();
        WinApi.User_32.ChangeDisplaySettingsEx(newPrimary.ScreenDevice.DeviceName, ref ndm6, (IntPtr)null, (int)WinApi.DeviceFlags.CDS_SET_PRIMARY | (int)WinApi.DeviceFlags.CDS_UPDATEREGISTRY, IntPtr.Zero);
    }


    private static WinApi.DEVMODE NewDevMode()
    {
        WinApi.DEVMODE dm = new WinApi.DEVMODE();
        dm.dmDeviceName = new String(new char[31]);
        dm.dmFormName = new String(new char[31]);
        dm.dmSize = (ushort)Marshal.SizeOf(dm);
        return dm;
    }
}